/**
 * @file STL_Log.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 日志控制器
 * @version 0.0.1
 * @date 2020-07-16
 * 
 * @coryright Copyright Sci-Tech Laboratories (c) 2020
 * 
 */

#include "STL_Log.hpp"
#include <stdarg.h>
#include <sys/timeb.h>
#include <memory.h>
#include "STL_Mutex.hpp"

#define LOG_CACHE_SIZE 1024

namespace stl
{
    LogLevel stl_level = kLogLevel_Debug;
    stl::Mutex s_LogMtx;

    char szTime[32] = {0};
    void genSzTime()
    {
        struct tm tmTime;
        struct timeb tb;
        ftime(&tb);
        localtime_r(&tb.time, &tmTime);
        int tmYear = tmTime.tm_year + 1900;
        int tmMon = tmTime.tm_mon + 1;
        int tmMday = tmTime.tm_mday;
        int tmHour = tmTime.tm_hour;
        int tmMin = tmTime.tm_min;
        int tmSec = tmTime.tm_sec;
        int tmMillisec = tb.millitm;
        memset(szTime, 0, 32 * sizeof(char));
        sprintf(szTime, "%04d-%02d-%02d %02d:%02d:%02d.%03d", tmYear, tmMon, tmMday, tmHour, tmMin, tmSec, tmMillisec);
    }

    void log(const char *format, ...)
    {
        char szBuffer[LOG_CACHE_SIZE] = {0};
        char *p = NULL;
        int prefixLength = 0;
        s_LogMtx.lock();
        genSzTime();
        prefixLength = sprintf(szBuffer, "[%s][  LOG] ", szTime);
        s_LogMtx.unlock();
        p = szBuffer + prefixLength;
        va_list ap;
        va_start(ap, format);
        vsnprintf(p, 1024 - prefixLength, format, ap);
        va_end(ap);
        printf("%s\n", szBuffer);
    }

    void trace(const char *format, ...)
    {
        if (stl_level > kLogLevel_Trace)
            return;
        char szBuffer[LOG_CACHE_SIZE] = {0};
        char *p = NULL;
        int prefixLength = 0;
        s_LogMtx.lock();
        genSzTime();
        prefixLength = sprintf(szBuffer, "[%s][TRACE] ", szTime);
        s_LogMtx.unlock();
        p = szBuffer + prefixLength;
        va_list ap;
        va_start(ap, format);
        vsnprintf(p, 1024 - prefixLength, format, ap);
        va_end(ap);
        printf("%s\n", szBuffer);
    }

    void debug(const char *format, ...)
    {
        if (stl_level > kLogLevel_Debug)
            return;
        char szBuffer[LOG_CACHE_SIZE] = {0};
        char *p = NULL;
        int prefixLength = 0;
        s_LogMtx.lock();
        genSzTime();
        prefixLength = sprintf(szBuffer, "[%s][DEBUG] ", szTime);
        s_LogMtx.unlock();
        p = szBuffer + prefixLength;
        va_list ap;
        va_start(ap, format);
        vsnprintf(p, 1024 - prefixLength, format, ap);
        va_end(ap);
        printf("%s\n", szBuffer);
    }

    void info(const char *format, ...)
    {
        if (stl_level > kLogLevel_Info)
            return;
        char szBuffer[LOG_CACHE_SIZE] = {0};
        char *p = NULL;
        int prefixLength = 0;
        s_LogMtx.lock();
        genSzTime();
        prefixLength = sprintf(szBuffer, "[%s][ INFO] ", szTime);
        s_LogMtx.unlock();
        p = szBuffer + prefixLength;
        va_list ap;
        va_start(ap, format);
        vsnprintf(p, 1024 - prefixLength, format, ap);
        va_end(ap);
        printf("%s\n", szBuffer);
    }

    void warn(const char *format, ...)
    {
        if (stl_level > kLogLevel_Warn)
            return;
        char szBuffer[LOG_CACHE_SIZE] = {0};
        char *p = NULL;
        int prefixLength = 0;
        s_LogMtx.lock();
        genSzTime();
        prefixLength = sprintf(szBuffer, "[%s][ WARN] ", szTime);
        s_LogMtx.unlock();
        p = szBuffer + prefixLength;
        va_list ap;
        va_start(ap, format);
        vsnprintf(p, 1024 - prefixLength, format, ap);
        va_end(ap);
        printf("%s\n", szBuffer);
    }

    void error(const char *format, ...)
    {
        if (stl_level > kLogLevel_Error)
            return;
        char szBuffer[LOG_CACHE_SIZE] = {0};
        char *p = NULL;
        int prefixLength = 0;
        s_LogMtx.lock();
        genSzTime();
        prefixLength = sprintf(szBuffer, "[%s][ERROR] ", szTime);
        s_LogMtx.unlock();
        p = szBuffer + prefixLength;
        va_list ap;
        va_start(ap, format);
        vsnprintf(p, 1024 - prefixLength, format, ap);
        va_end(ap);
        printf("%s\n", szBuffer);
    }

    void fatal(const char *format, ...)
    {
        if (stl_level > kLogLevel_Fatal)
            return;
        char szBuffer[LOG_CACHE_SIZE] = {0};
        char *p = NULL;
        int prefixLength = 0;
        s_LogMtx.lock();
        genSzTime();
        prefixLength = sprintf(szBuffer, "[%s][FATAL] ", szTime);
        s_LogMtx.unlock();
        p = szBuffer + prefixLength;
        va_list ap;
        va_start(ap, format);
        vsnprintf(p, 1024 - prefixLength, format, ap);
        va_end(ap);
        printf("%s\n", szBuffer);
    }

    void setLogLevel(LogLevel level)
    {
        stl_level = level;
    }

} // namespace stl
